package module.map.nodes
{
	import drongo.desktop.selector.SelectorEvent;
	import drongo.desktop.utils.CollisionsHelp;
	import drongo.model.events.ModelEvent;
	import drongo.model.propertys.ArrayProperty;
	import drongo.model.values.CollectionValue;

	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.ui.Keyboard;

	import module.map.Operations;
	import module.map.model.MapModel;
	import module.map.model.Propertys;

	import robotlegs.bender.extensions.mediatorMap.api.IMediatorMap;

	import ui.Map.UI_AreaNodeView;
	import ui.Map.UI_PointView;

	public class AreaNodeMediator extends BaseNodeMediator
	{

		private static const lineCommand:Vector.<uint> = new Vector.<uint>();
		private static const lineDatas:Vector.<Number> = new Vector.<Number>();

		private static var viewStartPoint:Point = new Point();
		private static var startPoint:Point = new Point();
		private static var endPoint:Point = new Point();

		private static var lastPoint:Point = new Point();
		private static var lastPointValue:CollectionValue;
		private static var currentPoint:Point = new Point();
		private static var currentPointValue:CollectionValue;

		private static var tempPoint0:Point = new Point();

		[Inject]
		public var view:UI_AreaNodeView;
		[Inject]
		public var mediatorMap:IMediatorMap;

		private var points:ArrayProperty;
		private var pointViews:Array;
		private var currentMap:MapModel;
		public function AreaNodeMediator()
		{
			super();
		}

		override public function initialize():void
		{
			super.initialize();
			currentMap = this.project.currentMap;
			this.points = this.view.data.Get(Propertys.POINTS) as ArrayProperty;
			this.pointViews = [];
			this.Init(this.view);

			this.RefreshView();
		}

		override public function destroy():void
		{
			super.destroy();
			this.RemoveEvents();
		}

		override protected function AddEvents():void
		{
			super.AddEvents();
			this.nodeData.addEventListener(ModelEvent.CHILD_VALUE_CHANGED, this.PropertyUpdateHandler);
			this.points.addEventListener(ModelEvent.CHILD_VALUE_CHANGED, this.PointsPropertyChanged);
			this.points.addEventListener(ModelEvent.ADD_CHILD, this.PointsPropertyChanged);
			this.points.addEventListener(ModelEvent.REMOVE_CHILD, this.PointsPropertyChanged);

			this.stage.addEventListener(KeyboardEvent.KEY_DOWN, KeyboardDownHandler);

			this.currentMap.selector.addEventListener(SelectorEvent.SELECTLIST_CHANGE, this.SelectListChanged);
		}

		override protected function RemoveEvents():void
		{
			super.RemoveEvents();
			this.nodeData.removeEventListener(ModelEvent.CHILD_VALUE_CHANGED, this.PropertyUpdateHandler);
			this.points.removeEventListener(ModelEvent.CHILD_VALUE_CHANGED, this.PointsPropertyChanged);
			this.points.removeEventListener(ModelEvent.ADD_CHILD, this.PointsPropertyChanged);
			this.points.removeEventListener(ModelEvent.REMOVE_CHILD, this.PointsPropertyChanged);

			this.stage.removeEventListener(KeyboardEvent.KEY_DOWN, KeyboardDownHandler);
			this.currentMap.selector.removeEventListener(SelectorEvent.SELECTLIST_CHANGE, this.SelectListChanged);
		}

		private function SelectListChanged(e:SelectorEvent):void
		{
			this.CallNextFrame(this.DrawSelected);
		}

		private function KeyboardDownHandler(e:KeyboardEvent):void
		{
			if (e.keyCode == Keyboard.ESCAPE)
			{
				if (ediatorMode)
				{
					this.nodeData.Update(Propertys.EDIATRO_MODE, 0);
				}
			}
			else if (e.keyCode == Keyboard.DELETE)
			{
				if (ediatorMode)
				{
					if (this.project.currentMap.selector.selectedList.length > 0)
					{
						this.project.undoSystem.executeOperation(Operations.REMOVE_POINT, {node: this.nodeData});
						this.project.currentMap.selector.resetSelectList();
					}
				}
			}
		}

		private function PointsPropertyChanged(e:ModelEvent):void
		{
			this.CallNextFrame(this.RefreshView);
		}

		private function PropertyUpdateHandler(e:ModelEvent):void
		{
			this.CallNextFrame(this.RefreshView);
		}

		private function RefreshView():void
		{
			this.view.x = this.nodeData.Get(Propertys.X).GetValue();
			this.view.y = this.nodeData.Get(Propertys.Y).GetValue();
			this.view.visible = this.nodeData.Get(Propertys.VISIBLE).GetValue() == 1;
			this.view.touchable=this.nodeData.Get(Propertys.LOCK).GetValue()==0;
			this.RefreshPoints();
			this.DrawArea();
			this.DrawBackground();
			this.DrawSelected();
		}

		private function RefreshPoints():void
		{
			// 清理老的
			var pointView:UI_PointView;
			for (var i:int = 0; i < this.pointViews.length; i++)
			{
				pointView = this.pointViews[i];
				pointView.removeFromParent();
				mediatorMap.unmediate(pointView);
			}
			var count:uint = this.points.length;
			var pointData:CollectionValue;
			for (var index:int = 0; index < count; index++)
			{
				pointView = UI_PointView.createInstance();
				pointData = this.points.GetAt(index) as CollectionValue;
				pointView.data = {node: this.nodeData, point: pointData};
				this.pointViews.push(pointView);
				this.view.addChild(pointView);
				mediatorMap.mediate(pointView);
			}
		}

		/**
		 * 绘制背景
		 */
		private function DrawBackground():void
		{
			this.view.m_background.graphics.clear();
			if (ediatorMode)
			{
				this.view.m_background.graphics.beginFill(0x000000, 0.5);
				this.view.m_background.graphics.drawRect(-30000, -30000, 60000, 60000);
			}
		}

		private function DrawSelected():void
		{
			this.view.m_selectLayer.graphics.clear();
			this.view.m_selectLayer.graphics.lineStyle(4, 0xFFFF00);
			var index:int = this.project.currentMap.selector.selectedList.indexOf(this.nodeData);
			if (index >= 0)
			{
				var currentPointData:CollectionValue;
				var lineCommands:Vector.<int> = new Vector.<int>();
				var lineData:Vector.<Number> = new Vector.<Number>();
				var count:uint = this.points.length;
				for (var i:int = 0; i < count; i++)
				{
					currentPointData = this.points.GetAt(i) as CollectionValue;
					// 绘制
					if (i == 0)
					{
						lineCommands.push(1);
					}
					else
					{
						lineCommands.push(2);
					}
					lineData.push(
							currentPointData.Get(Propertys.X).GetValue(),
							currentPointData.Get(Propertys.Y).GetValue()
						);
				}
				// 闭合
				currentPointValue = this.points.GetAt(0) as CollectionValue;
				lineCommands.push(2);
				lineData.push(
						currentPointValue.Get(Propertys.X).GetValue(),
						currentPointValue.Get(Propertys.Y).GetValue()
					);
				// 连线
				this.view.m_selectLayer.graphics.drawPath(lineCommands, lineData);
			}
		}

		/**
		 * 绘制连线
		 */
		private function DrawArea():void
		{
			this.view.m_lineLayer.graphics.clear();
			this.view.m_lineLayer.graphics.lineStyle(3, 0x00FF00);

			this.view.m_fillLayer.graphics.clear();
			this.view.m_fillLayer.graphics.lineStyle(1, 0x00FF00);
			this.view.m_fillLayer.graphics.beginFill(0x00FFCC, 0.5);

			var lineCommands:Vector.<int> = new Vector.<int>();
			var lineData:Vector.<Number> = new Vector.<Number>();

			var count:uint = this.points.length;
			var currentPointValue:CollectionValue;
			for (var index:int = 0; index < count; index++)
			{
				currentPointValue = this.points.GetAt(index) as CollectionValue;
				// 绘制
				if (index == 0)
				{
					lineCommands.push(1);
				}
				else
				{
					lineCommands.push(2);
				}
				lineData.push(
						currentPointValue.Get(Propertys.X).GetValue(),
						currentPointValue.Get(Propertys.Y).GetValue()
					);
			}
			// 闭合
			currentPointValue = this.points.GetAt(0) as CollectionValue;
			lineCommands.push(2);
			lineData.push(
					currentPointValue.Get(Propertys.X).GetValue(),
					currentPointValue.Get(Propertys.Y).GetValue()
				);
			// 连线
			this.view.m_lineLayer.graphics.drawPath(lineCommands, lineData);

			this.view.m_fillLayer.graphics.drawPath(lineCommands, lineData);
		}

		override protected function DragMouseDownHandler(e:MouseEvent):void
		{
			e.stopImmediatePropagation();
			e.stopPropagation();
			// 编辑模式下
			if (ediatorMode)
			{
				var mousePoint:Point = this.view.globalToLocal(this.stage.mouseX, this.stage.mouseY);
				// 如果点在点上了
				if (CheckPoint(mousePoint))
				{
					return;
				}
				// 点在线上
				if (this.CheckMouse(mousePoint))
				{
					this.project.undoSystem.executeOperation(Operations.ADD_POINT, {node: nodeData, lastPoint: lastPointValue, currentPoint: currentPointValue, mousePoint: mousePoint});
				}
				else
				{
					this.project.undoSystem.executeOperation(Operations.ADD_POINT, {node: nodeData, mousePoint: mousePoint});
				}
				return;
			}
			super.DragMouseDownHandler(e);
		}

		override protected function MouseDoubleClick(e:MouseEvent):void
		{
			this.project.currentMap.selector.resetSelectList();
			if (this.project.currentMap.selector.selectedList.indexOf(this.nodeData) < 0)
			{
				this.project.currentMap.selector.push(this.nodeData);
			}
			this.nodeData.Update(Propertys.EDIATRO_MODE, 1);
		}

		/**
		 * 检测鼠标与各点是否相近
		 */
		private function CheckPoint(mousePoint:Point, disMin:Number = 10):Boolean
		{
			var pointView:UI_PointView;
			for (var i:int = 0; i < this.pointViews.length; i++)
			{
				pointView = this.pointViews[i];
				tempPoint0.x = pointView.x;
				tempPoint0.y = pointView.y;
				// 距离要开平方，这里用距离的平方代替
				if (CollisionsHelp.DistanceDetection(mousePoint, tempPoint0, disMin))
				{
					return true;
				}
			}
			return false;
		}

		/**
		 * 检测鼠标点是否在线上
		 * @param mouse				鼠标位置
		 * @param distMin			最小距离
		 * @return
		 */
		private function CheckMouse(mouse:Point, distMin:Number = 5):Boolean
		{
			var dataLen:uint = this.points.length;
			var dist:Number;
			for (var i:int = 0; i < dataLen; i++)
			{
				currentPointValue = this.points.GetAt(i) as CollectionValue;
				if (i > 0)
				{
					lastPointValue = this.points.GetAt(i - 1) as CollectionValue;
					lastPoint.x = lastPointValue.Get(Propertys.X).GetValue();
					lastPoint.y = lastPointValue.Get(Propertys.Y).GetValue();
					currentPoint.x = currentPointValue.Get(Propertys.X).GetValue();
					currentPoint.y = currentPointValue.Get(Propertys.Y).GetValue();
					dist = CollisionsHelp.GetNearestDistance(mouse, lastPoint, currentPoint);
					// 在线段上
					if (dist < distMin)
					{
						return true;
					}
				}
			}
			return false;
		}

		private function get ediatorMode():Boolean
		{
			return this.nodeData.Get(Propertys.EDIATRO_MODE).GetValue() > 0;
		}
	}
}